home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1999 August / SGI Freeware 1999 August.iso / dist / fw_Tix.idb / usr / freeware / lib / tix4.1 / Control.tcl.z / Control.tcl
Encoding:
Text File  |  1999-01-26  |  11.6 KB  |  472 lines

  1. # Control.tcl --
  2. #
  3. #     Implements the TixControl Widget. It is called the "SpinBox"
  4. #     in other toolkits.
  5. #
  6. # Copyright (c) 1996, Expert Interface Technologies
  7. #
  8. # See the file "license.terms" for information on usage and redistribution
  9. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  10. #
  11.  
  12. tixWidgetClass tixControl {
  13.     -classname  TixControl
  14.     -superclass tixLabelWidget
  15.     -method {
  16.     incr decr invoke update
  17.     }
  18.     -flag {
  19.     -allowempty -autorepeat -command -decrcmd -disablecallback
  20.     -disabledforeground -incrcmd -initwait -integer -llimit
  21.     -repeatrate -max -min -selectmode -step -state -validatecmd
  22.     -value -variable -ulimit
  23.     }
  24.     -forcecall {
  25.     -variable -state
  26.     }
  27.     -configspec {
  28.     {-allowempty allowEmpty AllowEmpty false}
  29.     {-autorepeat autoRepeat AutoRepeat true}
  30.     {-command command Command ""}
  31.     {-decrcmd decrCmd DecrCmd ""}
  32.     {-disablecallback disableCallback DisableCallback 0 tixVerifyBoolean}
  33.     {-disabledforeground disabledForeground DisabledForeground #303030}
  34.     {-incrcmd incrCmd IncrCmd ""}
  35.     {-initwait initWait InitWait 500}
  36.     {-integer integer Integer false}
  37.     {-max max Max ""}
  38.     {-min min Min ""}
  39.     {-repeatrate repeatRate RepeatRate 50}
  40.     {-step step Step 1}
  41.     {-state state State normal}
  42.     {-selectmode selectMode SelectMode normal}
  43.     {-validatecmd validateCmd ValidateCmd ""}
  44.     {-value value Value 0}
  45.     {-variable variable Variable ""}
  46.     }
  47.     -alias {
  48.     {-llimit -min}
  49.     {-ulimit -max}
  50.     }
  51.     -default {
  52.     {.borderWidth             0}
  53.     {*entry.relief            sunken}
  54.     {*entry.width            5}
  55.     {*label.anchor            e}
  56.     {*label.borderWidth        0}
  57.     {*Label.font                   -Adobe-Helvetica-Bold-R-Normal--*-120-*}
  58.     {*Button.anchor            c}
  59.     {*Button.borderWidth        2}
  60.     {*Button.highlightThickness    1}
  61.     {*Button.takeFocus        0}
  62.     {*Entry.background        #c3c3c3}
  63.     }
  64. }
  65.  
  66. proc tixControl:InitWidgetRec {w} {
  67.     upvar #0 $w data
  68.  
  69.     tixChainMethod $w InitWidgetRec
  70.  
  71.     set data(varInited)      0
  72.     set data(serial)    0
  73. }
  74.  
  75. proc tixControl:ConstructFramedWidget {w frame} {
  76.     upvar #0 $w data
  77.  
  78.     tixChainMethod $w ConstructFramedWidget $frame
  79.  
  80.     set data(w:entry)  [entry $frame.entry]
  81.  
  82.     set data(w:incr) [button $frame.incr -bitmap [tix getbitmap incr] \
  83.     -takefocus 0]
  84.     set data(w:decr) [button $frame.decr -bitmap [tix getbitmap decr] \
  85.     -takefocus 0]
  86.  
  87. #    tixForm $data(w:entry) -left 0 -top 0 -bottom -1 -right $data(w:decr) 
  88. #    tixForm $data(w:incr) -right -1 -top 0 -bottom %50
  89. #    tixForm $data(w:decr) -right -1 -top $data(w:incr) -bottom -1
  90.  
  91.     pack $data(w:entry) -side left   -expand yes -fill both
  92.     pack $data(w:decr)  -side bottom -fill both -expand yes
  93.     pack $data(w:incr)  -side top    -fill both -expand yes
  94.  
  95.     $data(w:entry) delete 0 end
  96.     $data(w:entry) insert 0 $data(-value)
  97.  
  98.     # This value is used to configure the disable/normal fg of the ebtry
  99.     set data(entryfg) [$data(w:entry) cget -fg]
  100.     set data(labelfg) [$data(w:label) cget -fg]
  101. }
  102.  
  103. proc tixControl:SetBindings {w} {
  104.     upvar #0 $w data
  105.  
  106.     tixChainMethod $w SetBindings
  107.  
  108.     bind $data(w:incr) <ButtonPress-1> "tixControl:StartRepeat $w  1"
  109.     bind $data(w:decr) <ButtonPress-1> "tixControl:StartRepeat $w -1"
  110.  
  111.     # These bindings will stop the button autorepeat when the 
  112.     # mouse button is up
  113.     foreach btn "$data(w:incr) $data(w:decr)" {
  114.     bind $btn <ButtonRelease-1> "tixControl:StopRepeat $w"
  115.     }
  116.  
  117.     tixSetMegaWidget $data(w:entry) $w
  118.  
  119.     # If user press <return>, verify the value and call the -command
  120.     #
  121.     tixAddBindTag $data(w:entry) TixControl:Entry 
  122. }
  123.  
  124. proc tixControlBind {} {
  125.     tixBind TixControl:Entry <Return> {
  126.     tixControl:Invoke [tixGetMegaWidget %W] 1
  127.     }
  128.     tixBind TixControl:Entry <Escape> {
  129.     tixControl:Escape [tixGetMegaWidget %W]
  130.     }
  131.     tixBind TixControl:Entry <Up> {
  132.     [tixGetMegaWidget %W] incr
  133.     }
  134.     tixBind TixControl:Entry <Down> {
  135.     [tixGetMegaWidget %W] decr
  136.     }
  137.     tixBind TixControl:Entry <FocusOut> {
  138.     if {"%d" == "NotifyNonlinear" || "%d" == "NotifyNonlinearVirtual"} {
  139.         tixControl:Tab [tixGetMegaWidget %W] %d
  140.     }
  141.     }
  142.     tixBind TixControl:Entry <Any-KeyPress> {
  143.     tixControl:KeyPress [tixGetMegaWidget %W]
  144.     }
  145.     tixBind TixControl:Entry <Any-Tab> {
  146.     # This has a higher priority than the <Any-KeyPress>  binding
  147.     # --> so that data(edited) is not set
  148.     }
  149. }
  150.  
  151. #----------------------------------------------------------------------
  152. #                           CONFIG OPTIONS
  153. #----------------------------------------------------------------------
  154. proc tixControl:config-state {w arg} {
  155.     upvar #0 $w data
  156.  
  157.     if {$arg == "normal"} {
  158.     $data(w:incr)  config -state $arg
  159.     $data(w:decr)  config -state $arg
  160.     catch {
  161.         $data(w:label) config -fg $data(labelfg)
  162.     }
  163.     $data(w:entry) config -state $arg -fg $data(entryfg)
  164.     } else {
  165.     $data(w:incr)  config -state $arg
  166.     $data(w:decr)  config -state $arg
  167.     catch {
  168.         $data(w:label) config -fg $data(-disabledforeground)
  169.     }
  170.     $data(w:entry) config -state $arg -fg $data(-disabledforeground)
  171.     }
  172. }
  173.  
  174. proc tixControl:config-value {w value} {
  175.     upvar #0 $w data
  176.  
  177.     tixControl:SetValue $w $value 0 1
  178.  
  179.     # This will tell the Intrinsics: "Please use this value"
  180.     # because "value" might be altered by SetValues
  181.     #
  182.     return $data(-value)
  183. }
  184.  
  185. proc tixControl:config-variable {w arg} {
  186.     upvar #0 $w data
  187.  
  188.     if [tixVariable:ConfigVariable $w $arg] {
  189.        # The value of data(-value) is changed if tixVariable:ConfigVariable 
  190.        # returns true
  191.        tixControl:SetValue $w $data(-value) 1 1
  192.     }
  193.     catch {
  194.     unset data(varInited)
  195.     }
  196.     set data(-variable) $arg
  197. }
  198.  
  199. #----------------------------------------------------------------------
  200. #                         User Commands
  201. #----------------------------------------------------------------------
  202. proc tixControl:incr {w {by 1}} {
  203.     upvar #0 $w data
  204.  
  205.     if {$data(-state) != "disabled"} {
  206.     if {[catch {$data(w:entry) index sel.first}] == 0} {
  207.         $data(w:entry) select from end
  208.         $data(w:entry) select to   end
  209.     }
  210.     
  211.     tixControl:SetValue $w [$data(w:entry) get] 0 1
  212.     tixControl:AdjustValue $w $by
  213.     }
  214. }
  215.  
  216. proc tixControl:decr {w {by 1}} {
  217.     upvar #0 $w data
  218.  
  219.     if {$data(-state) != "disabled"} {
  220.     if {[catch {$data(w:entry) index sel.first}] == 0} {
  221.         $data(w:entry) select from end
  222.         $data(w:entry) select to   end
  223.     }
  224.  
  225.     tixControl:SetValue $w [$data(w:entry) get] 0 1
  226.     tixControl:AdjustValue $w [expr 0 - $by]
  227.     }
  228. }
  229.  
  230. proc tixControl:invoke {w} {
  231.     upvar #0 $w data
  232.  
  233.     tixControl:Invoke $w 0
  234. }
  235.  
  236. proc tixControl:update {w} {
  237.     upvar #0 $w data
  238.  
  239.     if [info exists data(edited)] {
  240.     tixControl:invoke $w
  241.     }
  242. }
  243.  
  244. #----------------------------------------------------------------------
  245. #                       Internal Commands
  246. #----------------------------------------------------------------------
  247.  
  248. # Change the value by a multiple of the data(-step)
  249. #
  250. proc tixControl:AdjustValue {w amount} {
  251.     upvar #0 $w data
  252.  
  253.     if {$amount == 1 && $data(-incrcmd) != ""} {
  254.     set newValue [tixEvalCmdBinding $w $data(-incrcmd) "" $data(-value)]
  255.     } elseif {$amount == -1 && $data(-decrcmd) != ""} {
  256.     set newValue [tixEvalCmdBinding $w $data(-decrcmd) "" $data(-value)]
  257.     } else {
  258.     set newValue [expr $data(-value) + $amount * $data(-step)]
  259.     }
  260.  
  261.     if {$data(-state) != "disabled"} {
  262.     tixControl:SetValue $w $newValue 0 1
  263.     }
  264. }
  265.  
  266. proc tixControl:SetValue {w newvalue noUpdate forced} {
  267.     upvar #0 $w data
  268.  
  269.     if {[$data(w:entry) selection present]} {
  270.     set oldSelection \
  271.         "[$data(w:entry) index sel.first] [$data(w:entry) index sel.last]"
  272.     }
  273.  
  274.     set oldvalue $data(-value)
  275.     set oldCursor [$data(w:entry) index insert]
  276.     set changed 0
  277.  
  278.  
  279.     if {$data(-validatecmd) != ""} {
  280.     # Call the user supplied validation command
  281.     #
  282.        set data(-value) [tixEvalCmdBinding $w $data(-validatecmd) "" $newvalue]
  283.     } else {
  284.     # Here we only allow int or floating numbers
  285.     #
  286.     # If the new value is not a valid number, the old value will be
  287.     # kept due to the "catch" statements
  288.     #
  289.     if [catch {expr 0+$newvalue}] {
  290.         set newvalue 0
  291.         set data(-value) 0
  292.         set changed 1
  293.     }
  294.  
  295.     if {$newvalue == ""} {
  296.         if {![tixGetBoolean -nocomplain $data(-allowempty)]} {
  297.         set newvalue 0
  298.         set changed 1
  299.         } else {
  300.         set data(-value) ""
  301.         }
  302.     }
  303.  
  304.     if {$newvalue != ""} {
  305.         # Change this to a valid decimal string (trim leading 0)
  306.         #
  307.         regsub {^[0]*} $newvalue "" newvalue
  308.         if [catch {expr 0+$newvalue}] {
  309.         set newvalue 0
  310.         set data(-value) 0
  311.         set changed 1
  312.         }
  313.         if {$newvalue == ""} {
  314.         set newvalue 0
  315.         }
  316.  
  317.         if [tixGetBoolean -nocomplain $data(-integer)] {
  318.         set data(-value) [tixGetInt -nocomplain $newvalue]
  319.         } else {
  320.         if [catch {set data(-value) [format "%d" $newvalue]}] {
  321.             if [catch {set data(-value) [expr $newvalue+0.0]}] {
  322.             set data(-value) $oldvalue
  323.             }
  324.         }
  325.         }
  326.         
  327.         # Now perform boundary checking
  328.         #
  329.         if {$data(-max) != "" && $data(-value) > $data(-max)} {
  330.         set data(-value) $data(-max)
  331.         }
  332.         if {$data(-min) != "" && $data(-value) < $data(-min)} {
  333.         set data(-value) $data(-min)
  334.         }
  335.     }
  336.     }
  337.  
  338.     if {! $noUpdate} {
  339.     tixVariable:UpdateVariable $w
  340.     }
  341.  
  342.     if {$forced || "x$newvalue" != "x$data(-value)" || $changed} {
  343.     $data(w:entry) delete 0 end
  344.     $data(w:entry) insert 0 $data(-value)
  345.     $data(w:entry) icursor $oldCursor
  346.     if {[info exists oldSelection]} {
  347.         eval $data(w:entry) selection range $oldSelection
  348.     }
  349.     }
  350.  
  351.     if {!$data(-disablecallback) && $data(-command) != ""} {
  352.     if {![info exists data(varInited)]} {
  353.         set bind(specs) ""
  354.         tixEvalCmdBinding $w $data(-command) bind $data(-value)
  355.     }
  356.     }
  357. }
  358.  
  359. proc tixControl:Invoke {w forced} {
  360.     upvar #0 $w data
  361.  
  362.     catch {
  363.     unset data(edited)
  364.     }
  365.  
  366.     if {[catch {$data(w:entry) index sel.first}] == 0} {
  367.     # THIS ENTRY OWNS SELECTION --> TURN IT OFF
  368.     #
  369.     $data(w:entry) select from end
  370.     $data(w:entry) select to   end
  371.     }
  372.  
  373.     tixControl:SetValue $w [$data(w:entry) get] 0 $forced
  374. }
  375.  
  376. #----------------------------------------------------------------------
  377. # The three functions StartRepeat, Repeat and StopRepeat make use of the
  378. # data(serial) variable to discard spurious repeats: If a button is clicked
  379. # repeatedly but is not hold down, the serial counter will increase
  380. # successively and all "after" time event handlers will be discarded
  381. #----------------------------------------------------------------------
  382. proc tixControl:StartRepeat {w amount} {
  383.     if {![winfo exists $w]} {
  384.     return
  385.     }
  386.  
  387.     upvar #0 $w data
  388.  
  389.     if {[catch {$data(w:entry) index sel.first}] == 0} {
  390.     $data(w:entry) select from end
  391.     $data(w:entry) select to   end
  392.     }
  393.  
  394.     if [info exists data(edited)] {
  395.     unset data(edited)
  396.     tixControl:SetValue $w [$data(w:entry) get] 0 1
  397.     }
  398.  
  399.     incr data(serial)
  400.  
  401.     tixControl:AdjustValue $w $amount
  402.  
  403.     if {$data(-autorepeat)} {
  404.     after $data(-initwait) tixControl:Repeat $w $amount $data(serial)
  405.     }
  406.  
  407.     focus $data(w:entry)
  408. }
  409.  
  410. proc tixControl:Repeat {w amount serial} {
  411.     if {![winfo exists $w]} {
  412.     return
  413.     }
  414.     upvar #0 $w data
  415.  
  416.     if {$serial == $data(serial)} {
  417.     tixControl:AdjustValue $w $amount
  418.  
  419.     if {$data(-autorepeat)} {
  420.        after $data(-repeatrate) tixControl:Repeat $w $amount $data(serial)
  421.     }
  422.     }
  423. }
  424.  
  425. proc tixControl:StopRepeat {w} {
  426.     upvar #0 $w data
  427.  
  428.     incr data(serial)
  429. }
  430.  
  431. proc tixControl:Destructor {w} {
  432.  
  433.     tixVariable:DeleteVariable $w
  434.  
  435.     # Chain this to the superclass
  436.     #
  437.     tixChainMethod $w Destructor
  438. }
  439.  
  440. # ToDo: maybe should return -code break if the value is not good ...
  441. #
  442. proc tixControl:Tab {w detail} {
  443.     upvar #0 $w data
  444.  
  445.     if {![info exists data(edited)]} {
  446.     return
  447.     } else {
  448.     unset data(edited)
  449.     }
  450.  
  451.     tixControl:invoke $w
  452. }
  453.  
  454. proc tixControl:Escape {w} {
  455.     upvar #0 $w data
  456.  
  457.     $data(w:entry) delete 0 end
  458.     $data(w:entry) insert 0 $data(-value)
  459. }
  460.  
  461. proc tixControl:KeyPress {w} {
  462.     upvar #0 $w data
  463.  
  464.     if {$data(-selectmode) == "normal"} {
  465.     set data(edited) 0
  466.     return
  467.     } else {
  468.     # == "immediate"
  469.     after 1 tixControl:invoke $w
  470.     }
  471. }
  472.